/**
 * @file
 * @author  Cameron Diver
 * @version 0.1
 * @brief A library to handle C strings easily
 * @section Description
 *
 * A library for handling strings transparently, with this library handling
 * memory, length and size. The functions provided will help with most things,
 * but the underlying C string is available if the functions are not enough. The
 * library has the advantage of being able to store anything, due to it not using
 * null bytes as delimiters
 */

#ifndef STRING_HEADER
#define STRING_HEADER

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "DynamicArray.h"

/* NOTE:
 *	The functions with Safe appended are the functions that should be used
 *	if the string may contain null bytes
 *	
 *	The functions with S appended are functions that work on another instantiation of
 *	this implementation, rather than char arrays
 */

/** 
 * @brief A structure to hold the string, and details about it.
 * Should always be used as a pointer with the functions
 */
typedef struct
{
	char *String; /**< The array that contains the string data. */
	int Length;	/**< The 'visible' length of the string, that is, the actual useful data. */
	int Size;	/**< The size of the array, how much it can currently hold, until it needs to be resized again. */
}S_String;

/** Returns the underlying C string. Note that this is not null byte delimited. */
//#define S_GetCString(Str)			(((char *)((S_String *)Str)->String))
/* The above has been replaced with a function that makes sure that a null byte is on the end of the string */
/** Returns the length of the string. Note that the length of the string is different to the size. */
#define S_GetStringLength(String)	((((S_String*)String)->Length))
/** Prints the string. This should only be used when the string is certain to not contain any null bytes.
 * If the string might contain null bytes, use S_PrintSafe.
 */
#define S_Print(Str) 				(printf("%s", (((S_String *)Str)->String)))
/** This gets the size of the String, that is how much it can contain before needing to be reallocated */
#define S_GetSize(Str) 				(((S_String *)Str)->Size)
/** This function returns the character that is at At */
#define S_At(Str, At) 				(char)(((S_String *)Str)->String[At])
/** This function capitalises the character at the start of the string, that is if it can be capitalised */
#define S_Capitalise(Str) 			do{if(((S_String *)Str)->Length>0&&islower(((S_String *)Str)->String[0]))\
									{((S_String *)Str)->String[0]=toupper(((S_String *)Str)->String[0]);}}while(0)

/** This function creates a new string and returns a pointer to it,
	and sets that strings value to the value passed with String
	@param String
		A string with which to fill the new S_String with
	@return 
		This function will return NULL on error, else it will return a pointer to a new S_String
*/
S_String *S_NewString(char *String);
/** This function is very similar to S_NewString, but this one accepts another parameter of length,
	which is used to allocate the string, and copy over the data.
	@param String
		A string with which to fill the new S_String with
	@param Length
		The length of the string that is used to create the new S_String
	@return
		A pointer to a new S_String object, or NULL on error
*/
S_String *S_NewStringSafe(char *String, int Length);
S_String *S_NewStringS(S_String *String);
/**
	This function will clear all of the resources that are being used by the S_String
	@param String
		The pointer to a S_String which will be freed
	@section Note
		This function can cause a double free or memory corruption if an invalid pointer is passed to it
*/
void S_FreeString(S_String *String);

/**
	This function is used to set an S_String object to the value of Str
	@Param String
		The pointer to an S_String object which will be set to the value of Str
	@param Str
		The value with which to set the S_String object
	@return 
		This function will return 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
*/ 
int S_SetString(S_String *String, char *Str);
/**
	This function is used to set an S_String object to the value of another S_String object
	@param String
		The pointer to S_String object which will be set to the value of SetString
	@param SetString
		The pointer to another S_String object, which will be used to set String
	@return
		This function will return 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
*/
int S_SetStringS(S_String *String, S_String *SetString);
/**
	This function is used to set an S_String object to the value of another S_String object
	@param String
		The S_String object which will have it's value changed
	@param Str
		The string that will be copied into String
	@param Length
		The length of the string Str, or however much of that string is to be used
	@return
		This function will return 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
		The safe functions have been provided for strings that may contain null bytes.
*/
int S_SetStringSafe(S_String *String, char *Str, int Length);

/**
	This function will append a string onto the given S_String object
	@param String
		The S_String object with which to append another string
	@param Str
		The string to append
	@return 
		This function will return 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
		Where possible, it is a lot faster to use S_Prepend* than the S_Append* functions
*/
int S_AppendString(S_String *String, char *Str);
/**
	This function will append one S_String object onto another S_String object
	@param String
		The S_String object with which to append another string
	@param AppendString
		The S_String object to append
	@return 
		This function will return 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
		Where possible, it is a lot faster to use S_Prepend* than the S_Append* functions
*/
int S_AppendStringS(S_String *Str, S_String *AppendString);
/**
	This function will append a string onto the given S_String object. This function will copy with a specified length
	@param String
		The S_String object with which to append another string
	@param Str
		The string to append
	@param Length
		The length of the string to be appended.
	@return 
		This function will return 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
		Where possible, it is a lot faster to use S_Prepend* than the S_Append* functions.
*/
int S_AppendStringSafe(S_String *String, char *Str, int Length);
int S_AppendChar(S_String *String, char C);
/**
	This function will insert a string into a S_String object.

	@param String
		The S_String object in which to insert the string
	@param Offset
		The offset to position the string
	@param Str
		The string to insert
	@return 
		This function returns 0 on success, or -1 on error
	
	@section Note
		This function will allocate more memory for the S_String object if it has to.
		
		The safe functions have been provided for strings that may contain null bytes.
*/
int S_InsertString(S_String *String, int Offset, char *Str);
/**
	This function will insert one S_String into another S_String object 
	@param String
		The S_String object in which to insert the string
	@param Offset
		The offset to position the string
	@param Str
		The S_String to insert
	@return 
		This function returns 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
*/
char *S_GetCString(S_String *Str);
int S_InsertStringS(S_String *Str, int Offset, S_String *InsertString);
/**
	This function will insert a string into a S_String object, with a specified length 
	@param String
		The S_String object in which to insert the string
	@param Offset
		The offset to position the string
	@param Str
		The string to insert
	@param Length
		The length of the string to insert
	@return 
		This function returns 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
		The safe functions have been provided for handling strings that contain null bytes.
*/
int S_InsertStringSafe(S_String *String, int Offset, char *Str, int Length);

/**
	This function is provided for printing a string that may contain null bytes
	@param String
		An S_String object which will be printed
*/
void S_PrintSafe(S_String *String);
/**
	This function prepends a string onto a S_String Object
	@param String
		The S_String object with which to prepend the string
	@param Str
		The string to prepend
	@return
		This function returns 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
*/
int S_PrependString(S_String *String, char *Str);
/**
	This function prepends one S_String onto another S_String Object
	@param String
		The S_String object with which to prepend the string
	@param Str
		The S_String object to prepend
	@return
		This function returns 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
*/
int S_PrependStringS(S_String *String, S_String *PString);
/**
	This function prepends a string onto a S_String Object, with a specified length
	@param String
		The S_String object with which to prepend the string
	@param Str
		The string to prepend
	@param Length
		The length of the string to be prepended
	@return
		This function returns 0 on success, or -1 on error
	@section Note
		This function will allocate more memory for the S_String object if it has to.
		The safe functions have been provided for working with strings that may contain null bytes.
*/
int S_PrependStringSafe(S_String *String, char *Str, int Length);

/* Original comment documentation here, new doxygen comment underneath */
/* This function will set how many bytes are currently allocated for the string.
	NOTE:	
		The bytes may be allocated but it does not mean they are being used.
	
		It is not neccesary to call this function before using a function which will
		increase the size of the string, this library will take care of that for you
*/
/**
	This function resizes (if neccesary) the given string using realloc
	@param String
		The S_String object to resize
	@param Size
		The size to resize the object to
	@return
		This function returns 0 on success, or -1 on failure.
	@section Note
		This function may not call realloc if the current size is equal to the size requested.
*/
int S_SetSize(S_String *String, int Size);

/* This function will return the memory that is residing at the S_String->String offset of At
	NOTE:
		This function will not check to see if memory bounds are being crossed. This is not
		laziness, this is a design choice because there would be no (nice, thread-friendly, re-entrant)
		way to return on error IMO. If anybody has any ideas, feel free to share
*/
//char S_At(S_String *String, int At); This function is now a macro

/* Original comment documentation here, new doxygen comment underneath */ /* TODOOOOOOOOO Doxygen comments... (and the actual functions) */
/* These functions will find first and last occurances of chars, strings or S_Strings.
	Functions appended with C work on chars
	Functions appended with S work on S_Strings
	Functions appended with nothing work on char arrays
	Functions appended with safe work on char arrays with given lengths.
	
	Functions which have FindFirst in their name find the first occurance of 
	entities, and expectedly FindLast finds the last occurance
	
	When no occurance is found, these functions return -1, and on success they return the offset
*/
int S_FindFirstC(S_String *String, char Search);
int S_FindLastC(S_String *String, char Search);
int S_FindFirst(S_String *String, char *Search);
int S_FindLast(S_String *String, char *Search);
int S_FindFirstS(S_String *String, S_String *Search);
int S_FindLastS(S_String *String, S_String *Search);
int S_FindFirstSafe(S_String *String, char *Search, int Length);
int S_FindLastSafe(S_String *String, char *Search, int Length);

/**
	This function reverses the given string
	@param String
		The string to reverse
	@section Note
		This function does the reversing in-place.
*/
void S_StringReverse(S_String *String);
/**
	This function converts all of the characters in the string to uppercase
	@param String
		The string to convert to uppercase
	@section Note
		This function does the converting in-place
*/
void S_ToUpper(S_String *String);
/**
	This function strips whitespace from the front and end of a string
	@param String
		The string to strip
	@section Note
		This function does the stripping in-place.
		If the length of the string changes in this function, it is updated
*/
void S_Strip(S_String *String);
/**
	This function pads the front of a string until the desired length is reached
	@param Str
		The string to pad
	@param Length
		The length to pad the string to
	@param PadChar
		The character used to pad the string
	@return
		This function will return 0 on success, or -1 on failure.
	@section Notes
		This function will try to allocate more memory for the S_String object if neccesary.
*/
int S_PadFront(S_String *Str, int Length, char PadChar);
/**
	This function converts the given string to an integer and returns it.
	@param String
		The string to convert to an integer
	@return
		The integer created from the string
	@section Note
		This function assumes that the given string contains a number in base 10.
		
		All character that are not 0-9 are ignored, and the function continues as if they were never there.
		
		This function checks for signed-ness at the start of the number. Note that (excluding whitespace) the sign has to be the first thing in the string.
		
		This functions create signed integers.
		
		The function does not attempt to round any fractions, it just converts the elements before the decimal point. 
		
		If the function fails, it will return 0.
*/
int S_ToInt(S_String *String);
/**
	This function converts a given string into a long integer, then returns it.
	@param String
		The string to be converted.
	@return
		A long version of the given string
	@section Note
		This function assumes that the given string contains a number in base 10.
		
		All character that are not 0-9 are ignored, and the function continues as if they were never there.
		
		This function checks for signed-ness at the start of the number. Note that (excluding whitespace) the sign has to be the first thing in the string.
		
		The function does not attempt to round any fractions, it just converts the elements before the decimal point. 
		
		This functions create signed integers.
		
		If the function fails, it will return 0.
*/
long S_ToLong(S_String *String);
/**
	This function converts a given string into a double precision floating point number, then returns it.
	@param String
		The string to be converted.
	@return
		A double version of the given string
	@section Note
		This function assumes that the given string contains a number in base 10.
		
		All character that are not 0-9 are ignored, and the function continues as if they were never there.
		
		This function checks for signed-ness at the start of the number. Note that (excluding whitespace) the sign has to be the first thing in the string.
		
		If the function fails, it will return 0.0.
*/
double S_ToDouble(S_String *String);
float S_ToFloat(S_String *String);

S_String *S_SubString(S_String *String, int Offset, int Length);

D_Array S_Explode(S_String *String, char C);

#endif
